/*
 * Copyright (c) 2025 Huawei Device, Inc. Ltd. and <马弓手>.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */


#include "Thread.h"
#include <errno.h>
#include <unistd.h>
#include <algorithm>
#include <sys/time.h>
///////////////////////////////////////////////////////////////////////
//class CThread
//
pthread_mutex_t CThread::m_mutexRun = PTHREAD_MUTEX_INITIALIZER;

vector<void*> CThread::m_ThreadList;

CThread::CThread()
{
	m_bStop = false;
	m_thread = 0;
	m_arg = NULL;
	pthread_mutex_init(&m_mutexStop, NULL);
}

CThread::~CThread()
{
	pthread_mutex_destroy(&m_mutexStop);
}

bool CThread::Start(void * arg, bool bJoinable)
{
	bool bResult = false;
	pthread_mutex_lock(&m_mutexStop);
  AddSelfToList();
	try
	{
		SetArg(arg);
		pthread_attr_t thread_attr;
		pthread_attr_init(&thread_attr);
		if (bJoinable)
		{
			pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_JOINABLE);
		}
		else
		{
			pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_DETACHED);
		}
		
		if (pthread_create(&m_thread, &thread_attr, &(CThread::EntryPoint), this) == 0)
			bResult = true;
		else
		{
      RemoveSelfFromList();
			bResult = false;
		}
	}
	catch(...)
	{
    RemoveSelfFromList();
		bResult = false;

	}
	pthread_mutex_unlock(&m_mutexStop);
	return bResult;
}

void CThread::Stop()
{
	SetStopFlag();
}

int CThread::Join(void **ppRetval)
{
	return pthread_join(GetThreadId(), ppRetval);
}

void CThread::Run(void * arg)
{
	try
	{
	  Setup();
	  Execute(arg);
	  ResetStopFlag();
    RemoveSelfFromList();
	}
	catch(...)
	{
	}
}

void * CThread::EntryPoint (void * pthis)
{
	try
	{
		CThread * pt = (CThread *)pthis;
		pt->Run(pt->GetArg());
	}
	catch(...)
	{
	}
	return NULL;
}

void CThread::Setup()
{
	//Anything you want to be executed before Execute().
}

bool CThread::GetStopFlag()
{
  bool bResult;
  pthread_mutex_lock(&m_mutexStop);
  bResult = m_bStop;
  pthread_mutex_unlock(&m_mutexStop);
  return bResult;
}

void CThread::SetStopFlag()
{
  pthread_mutex_lock(&m_mutexStop);
  m_bStop = true;
  pthread_mutex_unlock(&m_mutexStop);
}

void CThread::ResetStopFlag()
{
  pthread_mutex_lock(&m_mutexStop);
  m_bStop = false;
  pthread_mutex_unlock(&m_mutexStop);
}

void CThread::AddSelfToList()
{
  pthread_mutex_lock(&m_mutexRun);
	m_ThreadList.push_back(this);
  pthread_mutex_unlock(&m_mutexRun);
}

void CThread::RemoveSelfFromList()
{
    pthread_mutex_lock(&m_mutexRun);
    vector<void*>::iterator iter = find(m_ThreadList.begin(), m_ThreadList.end(), this);
    if(iter != m_ThreadList.end())
        m_ThreadList.erase(iter);
    pthread_mutex_unlock(&m_mutexRun);
}

bool CThread::IsRunning()
{
  bool bResult;
  vector<void*>::iterator iter;
  pthread_mutex_lock(&m_mutexRun);
  iter = find(m_ThreadList.begin(), m_ThreadList.end(), this);
  if (iter == m_ThreadList.end())
    bResult = false;
  else
    bResult = true;
  pthread_mutex_unlock(&m_mutexRun);
  return bResult;
}


///////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////
//class CThreadPool
CThreadPool::CThreadPool()
{
	m_arg = NULL;
	pthread_mutex_init(&m_mutexCond, NULL);
	pthread_cond_init(&m_cond, NULL);
	pthread_mutex_init(&m_mutexTask, NULL);
}

CThreadPool::~CThreadPool()
{
	pthread_mutex_destroy(&m_mutexCond);
    pthread_cond_destroy(&m_cond);
	pthread_mutex_destroy(&m_mutexTask);
}
bool CThreadPool::Start(void * arg)
{
	bool bResult = true;
	pthread_t thread;
	
	try
	{
		SetArg(arg);		
		for(int i=0; i<m_nPoolSize; i++)
		{
			pthread_attr_t thread_attr;
			pthread_attr_init(&thread_attr);	
			pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_DETACHED);
			if (pthread_create(&thread, &thread_attr, &(CThreadPool::EntryPoint), this) == 0)
				bResult = true;
			else
			{
				bResult = false;
				break;
			}
            pthread_attr_destroy(&thread_attr);//释放资源
		}
	}
	catch(...)
	{
		bResult = false;

	}
	return bResult;
}

bool CThreadPool::StartThread()
{
    bool bResult = false;
	pthread_t thread;
	try
	{
        pthread_attr_t thread_attr;
        pthread_attr_init(&thread_attr);	
        pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_DETACHED);
        if (pthread_create(&thread, &thread_attr, &(CThreadPool::EntryPoint), this) == 0) {
             bResult = true;
             m_nCurPoolSize++;
        }
        else
        {
            bResult = false;
        }
        pthread_attr_destroy(&thread_attr);//释放资源
	}
	catch(...)
	{
		bResult = false;

	}
	return bResult;
}

void CThreadPool::Stop()
{
	SetStopFlag();
	for(int i=0; i<m_nPoolSize; i++)
		DealTask();
}

bool CThreadPool::GetStopFlag()
{
  bool bResult;
  bResult = m_bStop;
  return bResult;
}

bool CThreadPool::GetThreadStop() 
{
    if(GetWaitingThreads() <= 0)
        return false;
    bool bResult = false;
    if(m_nPoolSize.load() < m_nCurPoolSize.load()) {
        m_nCurPoolSize--;
        bResult = true;
    }
    return bResult;
}
void CThreadPool::SetStopFlag()
{
  m_bStop = true;
}

void CThreadPool::ResetStopFlag()
{
  m_bStop = false;
}
void CThreadPool::Run(void * arg)
{
	try
	{
	  LoopTask(arg);
	  ResetStopFlag();
	}
	catch(...)
	{
	}
}

void CThreadPool::LoopTask(void *arg)
{
	while(true)
	{
		const void *pTask;
        int nTotalTask = 0;
		while((pTask = GetTask(nTotalTask)) == NULL) {
			pthread_mutex_lock(&m_mutexCond);
            m_nWaitingThread++;
			pthread_cond_wait(&m_cond,&m_mutexCond);
            m_nWaitingThread--;
			pthread_mutex_unlock(&m_mutexCond);
			if (GetStopFlag()) {
				return;
			}
		}
        void* pTmp = InitThreadData();
		Execute(pTask, nTotalTask, pTmp);
        DeInitThreadData(pTmp);
        if(GetThreadStop()) {
            break;
        }
	}
	return;
}

void * CThreadPool::EntryPoint (void * pthis)
{
	try
	{
		CThreadPool * pt = (CThreadPool *)pthis;
		pt->Run(pt->GetArg());
	}
	catch(...)
	{
	}
	return NULL;
}


void CThreadPool::AddTask(const void* arg)
{
	pthread_mutex_lock(&m_mutexTask);
	m_taskQue.push(arg);
	pthread_mutex_unlock(&m_mutexTask);
    if(GetWaitingThreads() > 0 || m_nCurPoolSize.load() >= MAX_THREAD_NUMBER_BOUNDARY) {
        DealTask();
    } else {
        StartThread();
    }
}

const void* CThreadPool::GetTask(int & nTotalTask)
{
	const void* pRet = NULL;
	pthread_mutex_lock(&m_mutexTask);
	if(!m_taskQue.empty()) {
		pRet = m_taskQue.front();
		m_taskQue.pop();
        nTotalTask = m_taskQue.size();
	}
	pthread_mutex_unlock(&m_mutexTask);
	return pRet;
}

void CThreadPool::SetPoolSize(const int nSize)
{
	m_nPoolSize = nSize;
    m_nCurPoolSize = nSize;
}

void CThreadPool::DealTask()
{
	pthread_cond_signal(&m_cond);
}

int CThreadPool::GetWaitingThreads()
{
    int count = 0;
    count = m_nWaitingThread.load();
    return count; 
}
int CThreadPool::GetCurPoolSize()
{
    int count = 0;
    count = m_nCurPoolSize.load();
    return count;
}
////////////////////////////////////////////////////////////////////////////////

//class CThreadStep
//

CThreadStep::CThreadStep()
{
	pthread_mutex_init(&m_mutexStep, NULL);
	pthread_cond_init(&m_cond, NULL);
}

CThreadStep::~CThreadStep()
{
	pthread_mutex_destroy(&m_mutexStep);
	pthread_cond_destroy(&m_cond);
}

bool CThreadStep::IsIdle()
{
	int nRet = pthread_mutex_trylock(&m_mutexStep);
	if (nRet == EBUSY)
		return false;
	else if (nRet == 0)
	{
		pthread_mutex_unlock(&m_mutexStep);
		return true;
	}
	else
	{
	  return false;
	}
}

void CThreadStep::NextStep()
{
	pthread_cond_signal(&m_cond);
}

void CThreadStep::Execute(void *arg)
{
	while(true)
	{
		pthread_cond_wait(&m_cond,&m_mutexStep);
		if (GetStopFlag())
		{
			pthread_mutex_unlock(&m_mutexStep);
			break;
		}
		StepTask(arg);
	}
}

void CThreadStep::Stop()
{
	CThread::Stop();
	pthread_cond_signal(&m_cond);
}


////////////////////////////////////////////////////////////////////
//class CThreadLoop
CThreadLoop::CThreadLoop()
{
	m_bPause = false;
	m_nSleepTime = 0;
	pthread_mutex_init(&m_mutexPause, NULL);
	pthread_mutex_init(&m_mutexLoop, NULL);
}

CThreadLoop::~CThreadLoop()
{
	pthread_mutex_destroy(&m_mutexPause);
	pthread_mutex_destroy(&m_mutexLoop);
}

void CThreadLoop::Stop()
{
	CThread::Stop();
}

void CThreadLoop::Pause()
{
	pthread_mutex_lock(&m_mutexPause);
	m_bPause = true;
	pthread_mutex_unlock(&m_mutexPause);
	while(!IsIdle())
	{
    timeval tv = {0, 200000};
    select(0, NULL, NULL, NULL, &tv);
	}
}

void CThreadLoop::Resume()
{
	pthread_mutex_lock(&m_mutexPause);
	m_bPause = false;
	pthread_mutex_unlock(&m_mutexPause);
}

bool CThreadLoop::GetPauseStatus()
{
	bool bPause;
	pthread_mutex_lock(&m_mutexPause);
	bPause = m_bPause;
	pthread_mutex_unlock(&m_mutexPause);
	return bPause;
}

bool CThreadLoop::IsIdle()
{
	int nRet = pthread_mutex_trylock(&m_mutexLoop);
	if (nRet == EBUSY)
		return false;
	else if (nRet == 0)
	{
		pthread_mutex_unlock(&m_mutexLoop);
		return true;
	}
	else
	{
	  return false;
	}
}

void CThreadLoop::Execute(void *arg)
{
	while(!GetStopFlag())
	{
		if (GetPauseStatus())
		{
      //sleep 50ms
      //usleep(50000); //this function in solaris may be not reliable
      timeval tv = {0, 50000};
      select(0, NULL, NULL, NULL, &tv);
			continue;
		}
		
  	pthread_mutex_lock(&m_mutexLoop);
		LoopTask(arg);
  	pthread_mutex_unlock(&m_mutexLoop);
		// don't sleep too long, replace with sleeping multitimes, 50ms per time
		if (m_nSleepTime > 0)
		{
			for(int i = 0; i <= m_nSleepTime/50 && !GetStopFlag() && !GetPauseStatus(); i++)
			{
        //at least sleep 50ms
        //usleep(50000); //this function in solaris may be not reliable
        timeval tv = {0, 50000};
        select(0, NULL, NULL, NULL, &tv);
			}
		}
	}
}
